#ifndef XGE_XSYNC_H_
#define XGE_XSYNC_H_
#include "xge_common_config.h"
#include "xbase_common.h"
#include "xatomic_operation.h"

#include <windows.h>

namespace xge{
  // Dummy lock 
  // this lock will do nothing
  class DummyLock{
  public:
    void Lock() {}
    bool TryLock(){ return true; }
    void UnLock(){}
  private:
    DISALLOW_COPY_AND_ASSIGN(DummyLock);
  };

  // Fast lock 
  // This lock is basically a simple wrapper for CRITICAL_SECTION
  // therefore it is a recursive lock as well as thread lock
  // not able to lock process .
  // We have no way to testify if there exist some other thread is waiting
  // for this lock .

  class FastLock {
  public:
    void Lock();
    bool TryLock();
    void Unlock();
    FastLock();
    ~FastLock();
    // If you want to make this lock reuse again like 
    // Drop all the locked stuff and 
    static bool ReinitializeXFastLock( FastLock* lock );
  private:
    // Critical section for locking the stuff
    ::CRITICAL_SECTION critical_section_;
    // indicator for weather it is initialized or not
    bool startup_;

    DISALLOW_COPY_AND_ASSIGN(FastLock);
  };

  // WaitableEvent
  // Using the wait to waiting for the event to be set
  // using the notify function to set the event
  // This locker is very slow , since it is the kernal level lock
  // avoid using it or use it on the place without considering the
  // performance

  class WaitableEvent {
  public:
    bool Notify();
    bool Reset ();
    const TripleResult Wait  ();
    const TripleResult Wait  ( size_t ms );
    // If you want to make this lock reuse again like 
    // Drop all the locked stuff and 
    static bool ReinitializeXWaitableEvent( WaitableEvent* event , bool manual = true , bool start_initialize = false );
  public:
    // manual : if this event is set by yourself or auto_reset 
    // start_initialize : if this event is start by notified 
    WaitableEvent( bool manual = true , bool start_initialize = false );
    ~WaitableEvent();
  private:

    ::HANDLE event_;

    DISALLOW_COPY_AND_ASSIGN(WaitableEvent);
  };

  // An auto locker for fast lock in scope
  // Pay attention : ONLY use it on the stack !
  template < typename Locker > class AutoLock {
  public:
    EXPLICIT_CTOR(AutoLock,Locker& lock):lock_(lock){
      lock.Lock();
    }
    ~AutoLock() {
      lock_.Unlock();
    }
  private:
    Locker& lock_;
    DISALLOW_COPY_AND_ASSIGN(AutoLock);
  };


  // Atomic flag
  // Using as the conditional variable synchronization way
  // Prefer FastLock to this
  class AtomicFlag{
  private:
    //flag
    volatile int flag_;
    enum {
      UNLOCKED = 0 ,
      LOCKED   = 1
    }
    ;
  public:

    AtomicFlag(){
      StoreAndRelease(flag_,0);
    }

    void Set() {
      AtomicOperation::AtomicSwap((volatile AtomicOperation::Atomic_t*)&flag_,AtomicFlag::LOCKED) ; 
    }
    void Unset(){
      AtomicOperation::AtomicSwap((volatile AtomicOperation::Atomic_t*)&flag_,AtomicFlag::UNLOCKED) ;
    }
    bool Get  (){
      return LoadAndAcquire(flag_) == 1 ;
    }
    bool TrySet(){
      return AtomicOperation::AtomicCAS((volatile AtomicOperation::Atomic_t*)&flag_,AtomicFlag::LOCKED,AtomicFlag::UNLOCKED) == AtomicFlag::UNLOCKED;
    }

  }
  ;

  // Prefer fast lock to this
  // Spin-lock , this lock is non-recursive lock !
  // You should pay-attention to this !!!!!!!!!!!

  class SpinLock {
  private:
    class LockBackoff {
    private:
      enum {
        LOOP_NOT_YEILD = 16 , //16 times is too many spin , reach here we may want to make it sleep a while
        LOOP_INC_TIMES = 2  , //the increase times of the spin count
      }
      ;
      size_t count_ ;
    public:
      //constructor
      LockBackoff(): count_(1) {}
      //pauseOnce
      void PauseOnce () {
        __asm pause
        return;
      }
      //pause any times
      void Pause();
      //reset the counter
      void Reset() {
        count_ = 1; 
      }
      //get the size of the count
      size_t Get() const {
        return count_;
      }
      //real pause 
      void PauseReal ( size_t times ) {
        AtomicOperation::Pause(times) ;
      }
    };

  public:
    void Lock();
    void Unlock();
    bool TryLock();
    bool TryLockSpinCount( size_t cnt );

  private:
    AtomicFlag flag_;

  };



}// namespace xge

#endif// XGE_XSYNC_H_